package com.ning.parking.service.impl;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ning.parking.config.CmdTypeEnum;
import com.ning.parking.domain.*;
import com.ning.parking.domain.VO.BillingResult;
import com.ning.parking.domain.VO.BillingTimeVO;
import com.ning.parking.domain.VO.OnPassVO;
import com.ning.parking.domain.dto.ParkingDTO;
import com.ning.parking.service.*;
import com.ning.parking.utils.PublishRoute;
import com.scsonic.common.domain.enter.CarTypeInfoVO;
import com.scsonic.common.enums.StatusEnum;
import com.scsonic.common.enums.caryardmanage.PeriodValidityTypeEnum;
import com.scsonic.common.enums.parking.*;
import com.scsonic.common.enums.parklot.DrivewayTypeEnum;
import com.scsonic.common.enums.trade.PayStatusEnum;
import com.scsonic.common.support.executor.GlobalExecutors;
import com.scsonic.framework.exception.BizException;
import com.scsonic.framework.util.DateUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Author ChenN
 * @Date 2025/3/12 13:31
 * @Version 0.0.1
 **/
@Slf4j
@Service
@AllArgsConstructor
public class OnPassImpl implements OnPassService {

    private final ParkingLotDrivewayInfoService parkingLotDrivewayInfoService;
    private final ParkingLotBaseInfoService parkingLotBaseInfoService;
    private final ParkingRecordService parkingRecordService;
    private final ParkingFeeCalculator parkingFeeCalculator;
    private final ParkingLotWhitelistService parkingLotWhitelistService;
    private final ParkingLotMonthlyApplyService parkingLotMonthlyApplyService;
    private final ParkingLotBlacklistService parkingLotBlacklistService;
    private final ParkingPayOrderService parkingPayOrderService;

    @Override
    public OnPassVO fillInRecordInfo(ParkingDTO parkingDTO) {

        ParkingRecord parkingRecord = parkingRecordService.getById(parkingDTO.getRecordId());

        ParkingLotDrivewayInfo one = new ParkingLotDrivewayInfo();
        one.setDrivewayCode("000000");
        one.setDrivewayId(-1L);
        one.setDrivewayName("补入默认通道");
        one.setDrivewayType(DrivewayTypeEnum.ENTRANCE);

        ParkingLotBaseInfo parkingLotBaseInfo = parkingLotBaseInfoService.getById(one.getParkingLotId());
        parkingRecord.builder(parkingLotBaseInfo, one, parkingDTO);
        CarTypeInfoVO carTypeInfoVO = CarTypeInfoVO.getDefault();
        parkingRecord.builderCarInfo(carTypeInfoVO);
        parkingRecord.setParkingStatus(ParkingStatusEnum.IN_PARKING);
        parkingRecordService.saveOrUpdate(parkingRecord);

        one = parkingLotDrivewayInfoService.getById(parkingDTO.getDrivewayId());
        OnPassVO exit = exit(parkingDTO, parkingRecord, one);
        return exit;
    }

    @Override
    public OnPassVO personnelCarExit(ParkingDTO parkingDTO) {
        ParkingRecord parkingRecord = parkingRecordService.getById(parkingDTO.getRecordId());
        ParkingLotDrivewayInfo one = parkingLotDrivewayInfoService.getById(parkingDTO.getDrivewayId());
        parkingDTO.setCaptureTime(new Date());
        parkingRecord.setExitTime(parkingDTO.getCaptureTime());
        OnPassVO exit = exit(parkingDTO, parkingRecord, one);
        return exit;
    }

    @Override
    public void billingTime(ParkingRecord record) {

      //List<ParkingLotMonthlyApply> monthlys = parkingLotMonthlyApplyService.selectMonthlyRecord(record);
    }

    @Override
    public OnPassVO onPass(ParkingDTO parkingDTO) {
        log.info("收到过车数据:{}", parkingDTO);

        String carLicense = parkingDTO.getCarLicense();
        try {
            String trim = carLicense.trim();
            carLicense = trim.replaceAll("\\r|\\n", "");
        } catch (Exception e) {
        }

        parkingDTO.setCarLicense(carLicense);

        if (parkingDTO.getIp() != null && parkingDTO.getIp().equals("import_info")) {
            parkingDTO.setIsImportInfo(Boolean.TRUE);
            parkingDTO.setIp(null);
        }

        String ip = parkingDTO.getIp();
        ParkingLotDrivewayInfo one = null;
        if (ObjectUtil.isEmpty(ip)) {
            String drivewayId = parkingDTO.getDrivewayId();
            one = parkingLotDrivewayInfoService.getById(Long.valueOf(drivewayId));
        } else {
            one = parkingLotDrivewayInfoService.lambdaQuery().eq(ParkingLotDrivewayInfo::getIp, ip).one();
        }

        parkingDTO.setDrivewayName(one.getDrivewayName());
        parkingDTO.setDrivewayType(one.getDrivewayType());

        if (ObjectUtil.isEmpty(one)) {
            throw new BizException("请选择通道入场车辆");
        }

        try {
            String uuid = IdUtil.simpleUUID();
            MDC.put("traceId", "[" + uuid + "]");
            MDC.put("driverName", "[" + parkingDTO.getDrivewayName() + "]");
            MDC.put("carLicense", "[" + parkingDTO.getCarLicense() + "]");

            if (one.getDrivewayType() == DrivewayTypeEnum.ENTRANCE) {
                return entrance(parkingDTO, one);
            }
            return exit(parkingDTO, one);
        } catch (IllegalArgumentException e) {
            OnPassVO onPassVO = new OnPassVO();
            onPassVO.setLedMsg("出场识别请重新识别");
            return onPassVO;
        } finally {
            MDC.remove("traceId");
            MDC.remove("driverName");
            MDC.remove("carLicense");
        }

    }

    private OnPassVO exit(ParkingDTO parkingDTO, ParkingLotDrivewayInfo one) {
        return exit(parkingDTO, null, one);
    }


    private OnPassVO exit(ParkingDTO parkingDTO, ParkingRecord record, ParkingLotDrivewayInfo one) {
        ParkingLotBaseInfo parkingLotBaseInfo = parkingLotBaseInfoService.getById(one.getParkingLotId());
        OnPassVO onPassVO = new OnPassVO();
        if (record == null && parkingDTO.getCarLicense() != null) {
            record = parkingRecordService.findInParkingParkingRecord(parkingDTO.getCarLicense(), parkingLotBaseInfo.getParkingLotId());
        }
        if (record == null) {
            ParkingRecord parkingRecord = new ParkingRecord();
            parkingRecord.builder(parkingLotBaseInfo, one, parkingDTO);
            CarTypeInfoVO carTypeInfoVO = CarTypeInfoVO.getDefault();
            parkingRecord.builderCarInfo(carTypeInfoVO);
            parkingRecord.setParkingStatus(ParkingStatusEnum.TO_BE_LEAVE);
            parkingRecordService.saveOrUpdate(parkingRecord);
            onPassVO.setLedMsg(parkingRecord.getCarLicense() + "无入场记录请联系管理员");
            PublishRoute.pushBroadcast(CmdTypeEnum.NO_RECORD, parkingRecord.getExitDrivewayId(), parkingRecord);
            return onPassVO;
        }

        record.builder(parkingLotBaseInfo, one, parkingDTO);

        ParkingLotBlacklist blacklist = null;
        //校验黑名单
        if ( ParkingCarTypeEnum.BLACKLIST == record.getParkingCarType()&&record.getCarTypeId() != null) {
            blacklist = parkingLotBlacklistService.getById(record.getCarTypeId());
        }
        //场内加入黑名单校验
        if (blacklist == null) {
            blacklist = parkingLotBlacklistService.selectBlacklist(record.getCarLicense(), record.getEntTime());
        }

        if (blacklist != null){
            record.setParkingType(ParkingTypeEnum.TEMP);
            record.setCarTypeId(blacklist.getBlacklistId());
            record.setCarTypeName(blacklist.getBlacklistName());
            record.setParkingCarType(ParkingCarTypeEnum.BLACKLIST);
        }

        if (blacklist != null && blacklist.getLimitExit() != null&& blacklist.getLimitExit() == StatusEnum.YES){
            onPassVO.setLedMsg(record.getCarLicense() + "黑名单车辆请联系管理员");
            record.setLedShow(onPassVO.getLedMsg());
            parkingRecordService.leave(record, ParkingStatusEnum.TO_BE_LEAVE);
            throw new BizException(onPassVO.getLedMsg());
        }

        BillingResult billingResult = parkingRecordService.billing(record.getRecordId());
        record.builderBilling(billingResult);
        if (billingResult.getPayStatus() == PayStatusEnum.PAY_SUCCESS || billingResult.getPayStatus() == PayStatusEnum.UN_NEED_PAY) {
            if (billingResult.getPayStatus() == PayStatusEnum.UN_NEED_PAY) {
                onPassVO.setLedMsg(record.getCarLicense() + "无需支付一路顺风");
                record.builderBilling(billingResult);
                record.setLedShow(record.getCarLicense() + "无需支付一路顺风");
                parkingRecordService.leave(record, ParkingStatusEnum.LEAVE);
                return onPassVO;
            }else if (billingResult.getPayStatus() == PayStatusEnum.PAY_SUCCESS){
                onPassVO.setLedMsg(record.getCarLicense() + "停车时长" + record.getParkingTime() + "已支付" + billingResult.getPayAmount()+ "元");
                record.setLedShow(onPassVO.getLedMsg());
                parkingRecordService.leave(record, ParkingStatusEnum.LEAVE);
                return onPassVO;
            }

        }
        onPassVO.setLedMsg(record.getCarLicense() + "停车时长" + record.getParkingTime() + "停车费用" + billingResult.getPayableAmount() + "元");
        record.setLedShow(onPassVO.getLedMsg());
        parkingRecordService.leave(record, ParkingStatusEnum.TO_BE_LEAVE);
        return onPassVO;
    }



    private OnPassVO entrance(ParkingDTO parkingDTO, ParkingLotDrivewayInfo one) {

        OnPassVO onPassVO = new OnPassVO();
        onPassVO.setLedMsg(parkingDTO.getCarLicense() + "欢迎光临");
        ParkingLotBaseInfo parkingLotBaseInfo = parkingLotBaseInfoService.getById(one.getParkingLotId());

        ParkingRecord inParkingParkingRecord = parkingRecordService.findInParkingParkingRecord(parkingDTO.getCarLicense(), parkingLotBaseInfo.getParkingLotId());

        //异步自动离场
        if (inParkingParkingRecord != null){
            autoExit(inParkingParkingRecord);
        }

        ParkingRecord parkingRecord = new ParkingRecord();
        parkingRecord.builder(parkingLotBaseInfo, one, parkingDTO);

        //黑名单全场生效
        ParkingLotBlacklist parkingLotBlacklist = parkingLotBlacklistService.selectBlacklist(parkingDTO.getCarLicense(), parkingDTO.getCaptureTime());
        if (parkingLotBlacklist != null) {
            CarTypeInfoVO carTypeInfoVO = CarTypeInfoVO.getDefault();
            carTypeInfoVO.setParkingType(ParkingTypeEnum.TEMP);
            carTypeInfoVO.setParkingCarType(ParkingCarTypeEnum.BLACKLIST);
            carTypeInfoVO.setCarTypeName(parkingLotBlacklist.getBlacklistName());
            StatusEnum limitEnter = parkingLotBlacklist.getLimitEnter();
            carTypeInfoVO.setCarTypeId(parkingLotBlacklist.getBlacklistId());
            if (limitEnter == StatusEnum.YES) {
                parkingRecord.setParkingStatus(ParkingStatusEnum.TO_BE_IN);
                parkingRecordService.saveOrUpdate(parkingRecord);
                onPassVO.setLedMsg(parkingRecord.getCarLicense() + "黑名单车辆无权限通行,请联系管理员");
                parkingRecord.setLedShow(onPassVO.getLedMsg());
                parkingRecord.builderCarInfo(carTypeInfoVO);
            }else {
                parkingRecord.builderCarInfo(carTypeInfoVO);
                parkingRecord.setParkingStatus(ParkingStatusEnum.IN_PARKING);
                parkingRecord.setLedShow(onPassVO.getLedMsg());
            }
        }else {
            CarTypeInfoVO carTypeInfoVO = getCarType(parkingDTO,onPassVO);
            parkingRecord.builderCarInfo(carTypeInfoVO);
            parkingRecord.setParkingStatus(ParkingStatusEnum.IN_PARKING);
            parkingRecord.setLedShow(onPassVO.getLedMsg());
        }
        parkingRecordService.saveOrUpdate(parkingRecord);
        onPassVO.setRecordId(parkingRecord.getRecordId());
        parkingRecord.setLedShow(onPassVO.getLedMsg());
        if (ParkingStatusEnum.IN_PARKING == parkingRecord.getParkingStatus()){
            parkingLotBaseInfoService.entSpace(parkingRecord.getParkingLotId());
        }
        PublishRoute.pushBroadcast(CmdTypeEnum.IN_CAR, parkingRecord.getEntDrivewayId(), parkingRecord);
        return onPassVO;
    }

    /**
     * 自动离场
     * @param inParkingParkingRecord
     */
    private void autoExit(ParkingRecord inParkingParkingRecord) {
        Date exitTime = inParkingParkingRecord.getExitTime();
        inParkingParkingRecord.setParkingStatus(ParkingStatusEnum.LEAVE);
        inParkingParkingRecord.setExitingType(ExitingTypeEnum.ENTRANCE_AUTO);
        if (exitTime != null && inParkingParkingRecord.getEntTime() != null) {
            BillingResult billingResult = parkingFeeCalculator.tempBilling(inParkingParkingRecord.getEntTime(), inParkingParkingRecord.getExitTime());
            inParkingParkingRecord.builderBilling(billingResult);
        }
        parkingRecordService.updateById(inParkingParkingRecord);

        List<ParkingRecord> list = parkingRecordService.lambdaQuery()
                .eq(ParkingRecord::getExitingType, ExitingTypeEnum.ENTRANCE_AUTO)
                .eq(ParkingRecord::getCarLicense, inParkingParkingRecord.getCarLicense())
                .list();

        if (list.size() >= 3) {
            List<ParkingLotBlacklist> blacklists = parkingLotBlacklistService.lambdaQuery().eq(ParkingLotBlacklist::getCarLicense, inParkingParkingRecord.getCarLicense()).list();

            if (ObjectUtil.isEmpty(blacklists)){
                ParkingLotBlacklist blacklist = new ParkingLotBlacklist();
                blacklist.setCarLicense(inParkingParkingRecord.getCarLicense());
                blacklist.setParkingLotId(inParkingParkingRecord.getParkingLotId());
                blacklist.setParkingLotName(inParkingParkingRecord.getParkingLotName());
                blacklist.setRemark("超过三次系统自动添加黑名单");
                blacklist.setLimitEnter(StatusEnum.YES);
                blacklist.setLimitExit(StatusEnum.YES);
                blacklist.setPrescription(PeriodValidityTypeEnum.FOREVER);
                blacklist.setCreateTime(DateUtils.date());
                blacklist.setCreateBy("System");
                blacklist.setUpdateBy("System");
                blacklist.setUpdateTime(DateUtils.date());
                parkingLotBlacklistService.save(blacklist);
                return;
            }
            ParkingLotBlacklist blacklist = blacklists.get(0);
            blacklist.setLimitEnter(StatusEnum.YES);
            blacklist.setLimitExit(StatusEnum.YES);
            blacklist.setPrescription(PeriodValidityTypeEnum.FOREVER);
            parkingLotBlacklistService.updateById(blacklist);
        }

    }

    private CarTypeInfoVO getCarType(ParkingDTO parkingDTO, OnPassVO onPassVO) {
        CarTypeInfoVO carTypeInfoVO = CarTypeInfoVO.getDefault();

        ParkingLotWhitelist parkingLotWhitelist = parkingLotWhitelistService.selectWhitlist(parkingDTO.getCarLicense(), parkingDTO.getCaptureTime(),parkingDTO.getParkingLotId());

        if (parkingLotWhitelist != null) {
            carTypeInfoVO.setParkingType(ParkingTypeEnum.WHITELIST);
            carTypeInfoVO.setParkingCarType(ParkingCarTypeEnum.WHITELIST);
            carTypeInfoVO.setCarTypeName(parkingLotWhitelist.getVehicleTypeName());
            carTypeInfoVO.setExceedCar(StatusEnum.NO);
            carTypeInfoVO.setCarTypeId(parkingLotWhitelist.getWhitelistId());


            PeriodValidityTypeEnum prescription = parkingLotWhitelist.getPrescription();

            if (prescription == PeriodValidityTypeEnum.FOREVER) {
                onPassVO.setLedMsg(parkingDTO.getCarLicense() + "永久白名单车辆");
                return carTypeInfoVO;
            }
            carTypeInfoVO.setStartTime(parkingLotWhitelist.getStartTime());
            carTypeInfoVO.setEndTime(parkingLotWhitelist.getEndTime());
            String s = DateUtil.formatBetween(parkingLotWhitelist.getEndTime(), parkingDTO.getCaptureTime(), BetweenFormatter.Level.DAY);
            onPassVO.setLedMsg(parkingDTO.getCarLicense() + "白名单车辆剩余时间"+s);
            return carTypeInfoVO;
        }

        ParkingLotMonthlyApply parkingLotMonthlyApply = parkingLotMonthlyApplyService.selectMonthly(parkingDTO.getCarLicense(), parkingDTO.getCaptureTime(),parkingDTO.getParkingLotId());

        if (parkingLotMonthlyApply != null) {
            carTypeInfoVO.setParkingType(ParkingTypeEnum.MONTHLY);
            carTypeInfoVO.setParkingCarType(ParkingCarTypeEnum.MONTHLY);
            carTypeInfoVO.setCarTypeName(parkingLotMonthlyApply.getMonthlyRuleName());
            carTypeInfoVO.setExceedCar(StatusEnum.NO);
            carTypeInfoVO.setStartTime(parkingLotMonthlyApply.getMonthlyStartDay());
            carTypeInfoVO.setEndTime(parkingLotMonthlyApply.getMonthlyEndDay());
            carTypeInfoVO.setCarTypeId(parkingLotMonthlyApply.getMonthlyId());
            String s = DateUtil.formatBetween(parkingLotMonthlyApply.getMonthlyEndDay(), parkingDTO.getCaptureTime(), BetweenFormatter.Level.DAY);
            onPassVO.setLedMsg(parkingDTO.getCarLicense() + "月租车辆剩余时间"+s);
            return carTypeInfoVO;
        }
        return carTypeInfoVO;
    }



}
